﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Qing.Lang {
    /*对自定义函数封装的对象*/
    public class Func {
        public List<Expr> Args; //参数列表
        public List<Expr> NamedArgs; //命名参数列表
        public Expr Code; //函数的执行体
        public bool Asy = false; //是否异步函数
        public Ctx? BindCtx = null; //函数绑定的语境
        public string Desc = "…"; //函数的描述信息

        public Func(List<Expr> args, Expr code, Ctx ctx) {
            Args = new List<Expr>();
            NamedArgs = new List<Expr>();

            foreach (var arg in args) {
                /*
                 * 对于创建时传入的参数列表
                 * 如果是变量类型，那么就是普通参数
                 * 如果是设值的中缀，那么就是命名参数
                 */
                if (arg.Tp == TP.Var) {
                    Args.Add(arg);
                } else if (arg.Tp == TP.Op && arg.Str() == "=") {
                    arg.List![1] = arg.List[1].Eval(ctx);
                    NamedArgs.Add(arg);
                } else if(arg.Tp == TP.Str) {
                    if(Desc == "…") {
                        Desc = arg.Str() + "。";
                    } else {
                        Desc += arg.Str() + "。";
                    }
                }
                
            }

            Code = code;
            if(ctx.Tp == CtxTp.Default) {
                BindCtx = ctx;
            } else {
                Ctx bctx = ctx.Dup();
                bctx.Father = ctx;
                BindCtx = bctx;
            }
        }


        /*这是调用自定义函数时调用的方法*/
        public Expr Run(List<Expr> realArgs, Ctx ctx) {
            /*调用函数，要创建函数执行的专用语境*/
            Ctx fctx;
            if(BindCtx != null) {
                fctx = new Ctx(BindCtx, CtxTp.Temp);
            } else {
                fctx = new Ctx(ctx, CtxTp.Temp);
            }

            List<Expr> realList = new List<Expr>(); //普通实参列表
            List<Expr> realNamed = new List<Expr>(); //命名实参列表

            foreach(var arg in realArgs) {
                /*对所有的实参进行求解，并区分时普通实参还是命名实参*/
                if(arg.Tp == TP.Op && arg.Str() == "=") {
                    arg.List![1] = arg.List![1].Eval(ctx);
                    realNamed.Add(arg);
                } else {
                    realList.Add(arg.Eval(ctx));
                }
            }

            /*把普通实参绑定到函数语境中*/
            for(int i=0; i<Args.Count; i++) {
                if(i<realList.Count) {
                    fctx.PutNow(Args[i].Str(), realList[i]);
                } else {
                    fctx.PutNow(Args[i].Str(), new Expr());
                }
            }

            /*把命名实参绑定到函数语境中*/
            foreach(var arg in NamedArgs) {
                fctx.PutNow(arg.List![0].Str(), arg.List![1]);
            }

            foreach(var arg in realNamed) {
                fctx.PutNow(arg.List![0].Str(), arg.List![1]);
            }

            if (Asy) {
                /*如果是异步函数，开启任务*/
                Task<Expr> task = new Task<Expr>(() => {
                    /*对执行体进行求解*/
                    Expr ans = Expr.EvalExprs(Code.List!, fctx);
                    if(ans.Tp == TP.Return) {
                        /*如果结果是返回类型的Expr，取出内部包装的返回值*/
                        return ans.Raw();
                    }
                    return ans;
                });
                task.Start();

                return new Expr(TP.Task, task);
            } else {
                /*对执行体进行求解*/
                Expr ans = Expr.EvalExprs(Code.List!, fctx);
                if (ans.Tp == TP.Return) {
                    /*如果结果是返回类型的Expr，取出内部包装的返回值*/
                    return ans.Raw();
                }
                return ans;
            }
            

        }

    }
}
